home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / ast_comp / strand88.txt < prev    next >
Text File  |  1993-07-04  |  61KB  |  1,385 lines

  1. Date: Mon, 3 Feb 92 15:09:01 -0800
  2. From: Jeff (Grambo) Graham <graham@TEETOT.ACUSD.EDU>
  3.  
  4.                 STRAND SOFTWARE TECHNOLOGIES, INC.
  5.                            STRAND88
  6.  
  7.                      TECHNICAL DESCRIPTION
  8.  
  9.                        Buckingham Release
  10.  
  11.                           July 1990
  12.  
  13.  
  14. SCOPE OF THIS DOCUMENT
  15.  
  16. This document provides a short technical description of STRAND88. Readers who
  17. are unfamiliar with the ideas of concurrency should read the companion
  18. document STRAND88 Technical Overview first This document is not intended to
  19. be a management level description.
  20.  
  21. STRAND AND STRAND88
  22.  
  23. The two terms Strand and STRAND88 have precise and different meanings. Strand
  24. is a language definition that is, by and large, in the public domain, such a
  25. definition covers only the language, its syntax and semantics but does not
  26. cover the environment or libraries.  STRAND88 is a product, currently the
  27. only available implementation of Strand, which includes an abstract machine
  28. emulator, compiler, lint, environment and associated services and libraries.
  29. STRAND88 has had a number of releases, the current release is called
  30. Buckingham, and is the second major release, the previous release was called
  31. Admiralty. Within a major release, minor updates occur, for example to
  32. support new hardware, these are referred to by build number. The initial
  33. Buckingham release has build number B.6. Very little in this document has
  34. been changed to reflect the upgrade from Admiralty to Buckingham.
  35.  
  36. Before describing the features of Strand it Is important to discard many of
  37. the conventional components of sequential languages. In a Strand system there
  38. are no stacks and hence no stack frames, variables behave quite unlike
  39. variables in C or Pascal, the concept of flow of control does not exist, and
  40. within some constraints, the semantics of a program are independent of the
  41. order that it is written.
  42.  
  43. STRAND FEATURES
  44.  
  45. Strand is a language that has parallel semantics, by this we mean that
  46. statements in Strand are executed concurrently, not in the order they occur
  47. in a procedure definition. Each statement, more accurately each procedure
  48. call, is executed in a separate process, on a particular processor. A process
  49. in this context is a far cry from a large scale process. Strand processes
  50. differ from other forms of process in the following ways. Firstly they are
  51. small, consuming only a few words of memory, secondly they only ever perform
  52. one operation, that is to spawn zero or more new processes, once this is
  53. performed the process is complete and can be recycled. Lastly they may have
  54. to wait for the correct set of inputs before they can execute
  55.  
  56. STRAND PROCESSES
  57.  
  58. A process has a set of arguments each one of which may be a data value
  59. (simple or structured) or a variable. Data structures may be referenced by
  60. more than one process, or one process argument may be a part of another data
  61. structure referenced in some other process. Variables may also be referenced
  62. by more than one process argument, that is they may be shared. A running
  63. Strand program therefore consists of a network of processes, connected by
  64. shared data structures and variables. There are no global structures. An
  65. alternative, and equally valid view, is that of a set of data structures
  66. being constructed in core by a set of processes, each process waiting to add
  67. its part of the edifice
  68.  
  69. One can represent a process as a term of the form:
  70.  
  71.         mod1:start(A1,A2,...Ak)
  72.  
  73. That is it has a name, start, is defined in a module, mod1, and arguments A1
  74. to Ak. We say that the number of arguments, k, is the arity of the process.
  75. Normally a process name is written in text with the arity appended, for
  76. example start/4, if start has an arity of 4. The reason for this is that
  77. Strand procedures with the same name but different arities are semantically
  78. distinct.
  79.  
  80. When a process executes, we use the term reduces, it may spawn new processes,
  81. some of which may be inbuilt procedures called kernels. Kernels are the
  82. primitive operations of Strand and perform various data manipulation
  83. activities.
  84.  
  85. VARIABLES
  86.  
  87. Variables in Strand are single assignment, and as mentioned in the previous
  88. paragraph may be shared, i.e. part of more than one process. Variables can be
  89. assigned a value. This replaces the variable with the value assigned, it is
  90. not possible to update this replacement once assignment has occurred
  91. Assignment is only performed by kernels, the most common being the assignment
  92. kernel itself. If an attempt is made to assign to a non-variable then a
  93. system error is generated. The effect of an assignment is that all process
  94. arguments that previously referenced a variable now reference the value
  95. assigned.
  96.  
  97. SHARED VARIABLES
  98.  
  99. Processes that share a variable may either be readers or writers, i.e. they
  100. may be waiting to use the value, or to write it. It is clear from the
  101. behavior of variable assignment that only one writer should ever exist for
  102. each variable and that multiple writers will lead to a system error. We are
  103. describing the lowest level semantics of Strand here, multiple writers are
  104. obviously an important programming technique, and can be achieved by higher
  105. level techniques.
  106.  
  107. MULTIPROCESSORS
  108.  
  109. Since the value assigned to a variable can not be changed it is always
  110. unambiguous to make a copy of the value on another processor. Therefore the
  111. situation of single writer and multiple readers where the readers are on
  112. different processors is exactly the same as if they were on the same
  113. processor. When an assignment is made, copies of the assigned value is
  114. communicated to the other processors. It merely takes a little longer to pass
  115. through the communications subsystem. To make one reader reduce on another
  116. node that reader process needs to be spawned on the desired node No other
  117. changes are necessary.
  118.  
  119. REDUCTION EXAMPLE
  120.  
  121. Suppose we had a process, called start, that spawned three processes, one
  122. writer, rite, and two readers, reeda and reedb, that share a variable 'X',
  123. then we can imagine the following series of events unfolding as execution
  124. proceeds (refer to diagram)
  125.  
  126.         -------------------------------------------------------------
  127.         | Time 0                start()                             |
  128.         -------------------------------------------------------------
  129.                 reduce start/0
  130.         -------------------------------------------------------------
  131.         | Time 1                rite(X)  -----------\               |
  132.         |                       reeda(X) ------------> Variable: X  |
  133.         |                       reedb(X) -----------/               |
  134.         -------------------------------------------------------------
  135.                 reduce rite/1
  136.         -------------------------------------------------------------
  137.         | Time 2                X := 42; -----------\               |
  138.         |                       reeda(X) ------------> Variable: X  |
  139.         |                       reedb(X) -----------/               |
  140.         -------------------------------------------------------------
  141.                 assign 42 to X
  142.         -------------------------------------------------------------
  143.         | Time 3                reeda(X) ------------> 42           |
  144.         |                       reedb(X) -----------/               |
  145.         -------------------------------------------------------------
  146.                 reduce reeda/1 and reedb/1
  147.         -------------------------------------------------------------
  148.         | Time 4                                                    |
  149.         -------------------------------------------------------------
  150.  
  151. At time 0 a single  process, start(), exists. Reducing this results in three
  152. processes, rite/1, reeda/1 and reedb/1. One process is then selected for
  153. reduction, we will assume it is rite/1, reducing this results in an
  154. assignment kernel being spawned [In the actual implementation kernels are
  155. normally executed 'in-line' for efficiency, the description here is a
  156. conceptual model]
  157. At time step 2 the assignment kernel, here shown as the assignment operator
  158. ':=' assigns 42 to the variable X. The two readers can now be reduced and
  159. read the value 42. Note that the reader processes can not reduce until the
  160. value is available. A process that is in this state is said to be suspended,
  161. in this case suspended on the variable X. Suspended processes wait quietly
  162. for the variable or variables they are waiting for to be assigned.
  163.  
  164. The reduction of a process is described by a procedure which is comprised of
  165. a set of clauses.
  166. Clauses have the following general form:
  167.  
  168.         H :- G1, G2,...Gm|B1, B2,...Bn                          m,n >= 0
  169.  
  170. Where H is the clause head, ':-' is known by convention as the implication
  171. operator, the Gs constitute the clause's guard, '|' is the commit operator
  172. and the Bs are the clause's body. The clause definition is terminated by a
  173. period.
  174. Clauses define basic process actions in the following way. The head and guard
  175. together specify a set of preconditions under which a process may be reduced.
  176. A clause of the form
  177.  
  178.         H :- G1, G2,...Gn|B1.
  179.  
  180. specifies that if its preconditions are met then the process changes to a new
  181. state as specified by B1. A general clause of the form
  182.  
  183.         H :- G1, G2,...Gm|B1, B2,...Bn
  184.  
  185. specifies that if the preconditions are met then the process changes to a
  186. state as specified by one of the body calls and simultaneously spawns or
  187. forks processes as specified by the other body calls.
  188.  
  189. CLAUSE STRUCTURE, PROCEDURE DEFINITIONS AND MODULES
  190.  
  191. The clause head describes a state which is used to match against the state of
  192. a process. it has the form
  193.  
  194.         H(T1, T2,...Tn)                         n>=0
  195.  
  196. The head consists of the name H (a string beginning with a lower case
  197. character) of the procedure to which the clause belongs and the argument list
  198. T1,T2,...Tn. The number of elements in the formal argument list is the arity.
  199.  
  200. The clause guard contains a sequence of guard kernel calls. A guard kernel
  201. call invokes a predefined test operation known as a guard kernel which is
  202. applied to the state of a given process. The language provides a set of guard
  203. kernels. It is also possible for the programmer to define user guard kernels
  204. using the foreign language interface . A guard kernel call has the form
  205.         G(T1, T2,...Tn)                         n>=0
  206.  
  207. A guard kernel call consists of the guard kernel name G (a string beginning
  208. with a lower case character) and an argument list.
  209. The clause body contains a collection of body calls and assignments (see
  210. below). A body call has the form
  211.  
  212.         B(T1, T2,...Tn)                         n>=0
  213.  
  214. Where B is the name of the procedure and n its arity and T1, T2,....Tn is its
  215. argument list. A body call can be one of:
  216.  
  217. -       a [body] kernel call. This invokes functionality provided by Strand the
  218.         language
  219. -       a procedure call [to a procedure defined in the same module (see below)]
  220. -       a system call [to the environment of the form C!]
  221. -       an external procedure call [of the form M:C]
  222.         (an external procedure call contains two components - a module M and a
  223.         call C to a procedure in the module)
  224. -       an addressed call [of the form C@N]
  225.         (an addressed call contains two components - an address N and an
  226.         indirect call C. The latter can be a system call or an external
  227.         procedure call).
  228.  
  229. A procedure definition is formed by grouping together clauses the heads of
  230. which have the same name and arity.
  231.  
  232. The code of a Strand program is composed of one or more modules. A module is
  233. a collection of procedures, the definition of compilation mode and an exports
  234. list. The exports list is a specification of the procedures contained in the
  235. module which may be referenced by procedures from other modules.
  236.  
  237. Generally, the structure of a Strand module can be viewed as:
  238.  
  239.         specification of compilation mode
  240.         specification of exports list
  241.  
  242.         procedure1
  243.  
  244.         procedure2 ...
  245.  
  246. The name of a module is determined by that of the file (with a .sam
  247. extension) from which it is loaded, and therefore must conform to the host
  248. operating system rules. The .sam suffix of compiled module files is assumed,
  249. and need not be specified.
  250.  
  251. Modules are developed using an external editor to write Strand source code
  252. files which conform to the structure described above. The source file must be
  253. compiled by the Strand compiler before the procedures they contain can be
  254. used. Strand source code files have the suffix .std. Compiled module files
  255. have the suffix .sam.
  256.  
  257. A module, once loaded, is a first class Strand  data type and can be
  258. manipulated by Strand programs in the same way as data types which can be
  259. represented directly in Strand source code.
  260.  
  261. DATA STRUCTURES IN STRAND
  262.  
  263. Tuples
  264.  
  265. Tuples are denoted by a collection of data items enclosed in braces i.e.{}
  266. and separated by commas. The arity of a tuple is the number of elements it
  267. contains. For example, the following tuple may represent a building:
  268.  
  269.         {house, 77,{bedrooms, 3}, Owner}
  270.  
  271. In this case the arity is 4 and the elements are: the string house, the
  272. number 77, the tuple {bedrooms, 3} and the variable Owner.
  273.  
  274. Lists
  275.  
  276. Lists are used to represent sequences of data items. A list is denoted by:
  277. [Head|Tail] where both Head and Tail are terms. The head of a list represents
  278. the first data item in the sequence; the tail represents the rest of the
  279. sequence. An empty list (i.e. one that has no head or tail) is denoted by:[].
  280. For example
  281.  
  282.         [house, 77, {bedrooms, 3}, Owner]
  283.  
  284. denotes a list which contains the same data as the example tuple shown above.
  285.  
  286. It must be understood that the tuple shown above and the list described here
  287. are completely different data structures even though they contain the same
  288. data items.
  289.  
  290. It is often valuable to be able to denote the continuation of a sequence
  291. without mentioning its elements explicitly, e.g.
  292.  
  293.         [house, 77 | Rest]
  294.  
  295.  
  296. AN EXAMPLE STRAND PROGRAM
  297.  
  298. This section provides a complete Strand program which allows illustration of
  299. most of the terminology introduced previously.
  300.  
  301. % This module 'member' implements the procedure member/3 which is
  302. % used to determine whether a data item is present in a list.
  303.  
  304. % Its format is - member(Item?, List?, Result^) - where Item and
  305. % List are input arguments and Result is an output argument which
  306. % is assigned the value 'true' or 'false' depending on whether Item
  307. % is present in List.
  308. % If List is not a list, Result is the value [] and an error is
  309. % signalled.
  310.  
  311. -compile(free).% compilation mode
  312. -exports([member/3]). % exports list
  313.  
  314. member(_,[],Result) :- Result := false    % C1 Item not found in
  315.                                           % List.
  316. member(X,[X|_],Result) :- Result := true  % C2 Item is first                
  317.                                           % element in List.
  318. member(X,[Y| Rest],Result) :-             % C2 Item not first
  319.         X =\= Y|                          % element in List
  320.                                           % so search rest of list.
  321. member(X, Rest, Result).
  322. member(_, IncorrectInput, Result) :-      % C4 for debugging. Trap
  323.         otherwise|                        % cases where second arg
  324.         Result := [],                     % is not a list. Send error
  325.         error('arg not a list '           % message and set Result to
  326.                 ,IncorrectInput)!.        % empty list to allow other
  327.                                           % process waiting for
  328.                                           % Result to react.
  329.  
  330. Notice the following points:
  331. 1.      C1 and C2 and C3 all use the anonymous variable as a formal variable to
  332.         indicate they do not care about the value of a formal argument.
  333.  
  334. 2.      C3 uses the formal variable Rest as an actual argument in the recursive
  335.         procedure call to member.
  336.  
  337. 3.      C3 makes a guard kernel call to the guard kernel '=\=' and C4 makes a
  338.         guard kernel call to the guard kernel 'otherwise'.
  339.  
  340. 4.      C4 makes a system call to notify the occurrence of an error.
  341.  
  342. 5.      C1, C2 and C3 all use a literal structure as a formal argument in each
  343.         case this structure is used to match against a process argument to
  344.         determine whether the clause can be used to reduce the process (matching
  345.         is covered in detail in the next section).
  346.  
  347. 6.      C1 and C2 both use the assignment operator ':=' to assign a literal
  348.         value to a formal variable. (Assignment is covered in more detail in the
  349.         next section.)
  350.  
  351.  
  352. STRAND PROGRAM EXECUTION
  353.  
  354. A Strand computation corresponds to a pool of concurrently executing
  355. processes Recall that each process can be represented by a term of the form:
  356.  
  357.         p(T1, T2,...Tn)                 (n>=0)
  358.  
  359. Where p/n identifies a procedure used to execute the process by its name and
  360. arity and T1,...., Tn are the process arguments. The arguments are data
  361. structures that comprise the state of the process. Computation proceeds by
  362. repeatedly removing a process from the pool and attempting to reduce it.
  363. Notice that this description does not preclude the possibility of
  364. simultaneously attempting to reduce more than one process.
  365.  
  366. A reduction attempt involves finding a clause from the associated procedure
  367. definition whose head matches the process state and the execution of the
  368. clause's guard. If the preconditions specified by a given clause head and
  369. guard are satisfied then the process commits to that particular clause. There
  370. may be more than one clause whose head matches the process state, in this
  371. instance the first one matching would be selected. It is important that the
  372. programmer realize this since it imposes a requirement for an appropriate
  373. degree of specificity in the definition of the preconditions of clauses. It
  374. also serves to explain the need for guards in addition to the matching
  375. process.
  376.  
  377. Once a process commits to a clause it is reduced. Recall that reduction
  378. involves only three kinds of action: termination, changing state and forking.
  379.  
  380. MATCHING
  381.  
  382. Strand employs a matching algorithm to compare a clause head with a process
  383. state. A process state matches with a clause head if the name of the
  384. procedure associated with the process is the same as the name of the clause
  385. head and the number of process arguments is the same as the number of the
  386. clause's formal arguments and the process arguments match with the formal
  387. arguments.
  388.  
  389. Strings match if the two strings are identical - they contain exactly the
  390. same sequence of characters.
  391.  
  392. Numbers only match if they are identical. In addition integers do not match
  393. against their real counterparts. It is normally dubious practice to match two
  394. real numbers.
  395.  
  396. Variables match against variables.
  397.  
  398. Structures match if they are of the same size and type and the elements they
  399. contain match. Thus a tuple can only match against a tuple of the same arity
  400. and a list can only match against a list as long as the specified elements
  401. match.
  402.  
  403. Although the matching algorithm may bind variables in the clause head, it may
  404. not assign values to variables in the process state.
  405.  
  406. An important concept for Strand programming is data flow synchronization
  407. where matching is suspended until sufficient data is available to determine
  408. the outcome of a match. In essence, it is the availability of data that
  409. determines when processes are able to execute
  410.  
  411. GUARD EXECUTION
  412.  
  413. We have previously mentioned guard kernels and guard kernel calls. A guard
  414. kernel call appears in the guard of a clause and invokes the test operation
  415. specified by the guard kernel. These tests are built into Strand and can be
  416. used to perform type checking, arithmetic comparison and term comparison.
  417. Like matching they serve to constrain when a clause can be used to reduce a
  418. process.
  419.  
  420. Any number of guard kernel calls may appear in the guard of a clause. They
  421. are executed from left to right textually after matching is complete and has
  422. succeeded. Each test may succeed, fail or suspend. If all tests In a guard
  423. succeed then the guard as a whole is said to succeed; if any test fails or
  424. suspends then the guard as a whole immediately fails or suspends
  425. respectively. Tests generally suspend if they encounter a variable.
  426.  
  427. The guard tests fall into five basic categories. These are:
  428.  
  429.         data type tests 
  430.         comparisons
  431.         assignment tests (does the variable have a value or not)
  432.         failure of match and guard tests in all other clauses
  433.         system state tests.
  434.  
  435. ASSIGNMENT
  436. Assignment is used to generate a value for a variable that appears in a
  437. process argument or to generate a value for a local variable. Remember a
  438. variable matches against a variable.
  439.  
  440. Assignment is represented in program text as follows:
  441.  
  442.         Variable := Value
  443.  
  444. Assignment calls can only appear in the body of a clause.
  445.  
  446. One way to visualize the assignment operation is to think of a variable as a
  447. box. The box has a label which corresponds to its name and it can hold any
  448. data structure. The effect of executing an assignment is to place a value in
  449. this box; any part of a program which refers to the variable via its label
  450. can access its value.
  451.  
  452. Although this operation is simple there are some subtler points that must be
  453. appreciated. Once a value has been assigned to a variable it cannot be
  454. removed or changed. Variables which have this property are often called
  455. single assignment variables.
  456.  
  457. Since it is possible to assign anything to a variable it must be possible to
  458. assign a variable to a variable. For example consider the assignment
  459.  
  460.         Thing1 :=  Thing2
  461.  
  462. After this assignment, any part of the program that refers to thing1
  463. automatically has access to the 'box' associated with Thing2. Another way to
  464. think of this is that Thing1 becomes an alias (i.e. another name) for Thing2.
  465.  
  466. Finally, a 'box' cannot be placed inside itself; indeed anything containing
  467. a box cannot be placed inside that 'box'. Thus the assignments Foo := Foo and
  468. Foo := [Baz, Bar, Foo] are defined to be illegal. Another way of putting this
  469. is that circular references and circular terms cannot be manipulated in
  470. Strand.
  471.  
  472. BODY CALLS
  473.  
  474. The distinction between a body kernel call and a procedure call is simply
  475. that body kernel calls invoke functionality specified by the language,
  476. whereas procedure calls refer to procedures defined by the programmer.
  477.  
  478. The exact details of what takes place given a body kernel call is
  479. implementation specific. However, in order to retain the simplicity of the
  480. model presented so far it is sufficient to say that the system attempts to
  481. 'reduce' the 'process' associated with a body kernel immediately without
  482. placing it in the process pool. It is only if the 'reduction' attempt
  483. suspends that a process is placed in the process pool.
  484.  
  485. Now let us look in more detail at procedure calls. Recall that once a process
  486. has committed to a particular clause there are only three kinds of action
  487. that can be taken to reduce the process. We have already seen how the general
  488. form of the body is related to each of these actions. All we need to do now
  489. is describe in slightly more detail how a procedure call is related to a
  490. change of state in a process and the spawning of further processes.
  491.  
  492. One of the procedure calls in the body causes the process to change state if
  493. we recall that a process can be represented by a term of the form
  494.  
  495.         p(T1, T2,... Tn)                n>=0
  496.  
  497. and a procedure call has the general form
  498.  
  499.         b(T1, T2,... Tn)                n>=0
  500.  
  501. It is easy to see that the process is transformed so that it is associated
  502. with the procedure definition that has the same name and arity as the
  503. procedure call and the process arguments now become those specified by the
  504. actual arguments of the procedure call. The data structures that become the
  505. process arguments are comprised of the literal values that appeared in the
  506. call plus the values that any variables might have received (which might
  507. themselves be variables) through matching or assignment and any local
  508. variables introduced in the clause that appear in the call. When the process
  509. has been thus transformed it is placed back in the process pool to be further
  510. reduced.
  511.  
  512. STRAND88 THE PRODUCT
  513.  
  514. STRAND88 as a product consists of more than just a strand compiler and
  515. abstract machine emulator, it also provides an interactive shell and an
  516. environment to aid software development.
  517.  
  518. The Strand Abstract Machine emulator, or SAM, is the part of the system that
  519. performs the low level emulation. This is designed to run on a variety of
  520. machines and enables compiled Strand code to be run on any SAM
  521. implementation. When strand is started by typing 'st' to the operating system
  522. prompt, it is the SAM that is invoked.
  523.  
  524. The services provide functions such as intermodule calling, I/O, and
  525. monitoring computations.
  526.  
  527. The shell provides an user interface and starts applications, compilations
  528. and other utility programs.
  529.  
  530.  
  531. EXAMPLE SHELL SESSION
  532.  
  533. Strand is started by typing the following command in response to the OS
  534. prompt:
  535.  
  536.         st
  537.  
  538. The first thing you see when Strand starts running is something like this:
  539.  
  540.         Welcome to STRAND88(TM). ...
  541.         Copyright (c) Artificial Intelligence Limited ...
  542.  
  543.         1 node invoked.
  544.         1>
  545.  
  546. The 1> is the STRAND88 Shell service prompt.
  547.  
  548. Suppose that the file demo1.std has the following contents:
  549.  
  550.         -compile(free).
  551.         -exports([min/3]).
  552.  
  553.         min(X,Y,Z):-
  554.                 X < Y |
  555.                         Z := X.
  556.         min(X,Y,Z):-
  557.                 X >= Y |
  558.                         Z := Y.
  559.         min(X,Y,Z):-
  560.                 otherwise |
  561.                         Z := error("illegal values",X,Y).
  562.  
  563.  
  564. Lets start by calling the min procedure that is defined in the demo1 module.
  565. We must tell Strand where the definition of the call can be found, the call
  566. we want to use and any arguments. Normally it is necessary to compile a
  567. module before it can be called, but we can assume that demo1 has been
  568. compiled already.
  569.  
  570.         1>demo1:min(23,45,Z)
  571.  
  572. Strand responds with:
  573.  
  574.         [started,1]
  575.         [exited,1]
  576.         2>
  577.  
  578. Strand has started the correct definition of the min call to use, reduced it
  579. to its kernel components and executed them. The started and exited text shows
  580. you that the call typed on input line 1 has been started and exited The 2> is
  581. Strand's prompt for another input, this time on the next line.
  582.  
  583. For simplicity, the rest of this document ignores strand's response of
  584. started and exited.
  585.  
  586. The minimum of 23 and 45 has been assigned to the variable Z but we have not
  587. seen the result yet. This variable is remembered by the shell, and whenever
  588. the shell sees Z in the future it will substitute the appropriate value.
  589. There are a number of ways in which we can examine the value of such shell
  590. variables. The easiest mechanism is to use the watch facility. This requests
  591. that the value assigned to a variable be displayed when that value is
  592. assigned. In other words the result of the watch request may not be seen for
  593. a long time, if the assignment is not performed for a while. If a value has
  594. already been assigned then it is printed immediately the request is made. A
  595. watch request is made by using the postfix operator '^'.
  596.  
  597.         3>Z^
  598.         Z == 23
  599.         4>
  600.  
  601. Shell variables can also be assigned directly:
  602.  
  603.         4>X := 123
  604.         5>
  605.  
  606. Now we can call min again, this time using the new shell variable X, and
  607. requesting a watch on a new variable Z2:
  608.  
  609.         7>demo1:min(34,12.3,Z2^)
  610.         Z2 == 12.3
  611.         8>
  612.  
  613. The demo2 module contains definitions for a procedure that recursively
  614. generates a list of integers. The module looks like this:
  615.  
  616.         -compile(free).
  617.         -exports([gen/2]).
  618.  
  619.         gen(0,X) :-
  620.                 X := [].
  621.         gen(N,X) :-
  622.                 N > 0 |
  623.                 X := [N|X1],
  624.                 N1 is N - 1,
  625.                 gen(N1,X1).
  626.         gen(N,X) :-
  627.                 otherwise |
  628.                         X := error("not an integer",N).
  629.  
  630. This module contains the procedure that defines the gen procedure, which has
  631. three clauses. The first clause simply assigns the variable X to an empty
  632. list if the first parameter is zero.
  633.  
  634. The second clause is more complicated. This definition may be used when the
  635. first clause cannot be used. This condition is checked with the "N>0" guard.
  636. When Strand uses this definition, it makes X a list whose first element is
  637. the value of N and whose second element is an unassigned variable called X1.
  638. Another new variable, N1, is created which is one less than the value of N.
  639. The definition concludes by calling gen again, this time with the new
  640. parameters. By repeated recursion the list is extended until N is zero, when
  641. the first clause is used to terminate the list correctly.
  642.  
  643. The third clause is invoked if the first parameter is not an integer, and
  644. assigns the output parameter to an error structure.
  645.  
  646. To generate a list of 10 integers, and see the result, we can type in the
  647. following:
  648.  
  649.         9>demo2:gen(10,I^)
  650.         [I/1, 10]
  651.         [I/2, 9]
  652.         [I/3, 8]
  653.         [I/4, 7]
  654.         [I/5, 6]
  655.         [I/6, 5]
  656.         [I/7, 4]
  657.         [I/8, 3]
  658.         [I/9, 2]
  659.         [I/10, 1]
  660.         [I/tail,[],'at index', 10]
  661.         10>
  662.  
  663. Procedures such as gen/2 that create a list, or stream, are referred to as
  664. producers, and normally are coupled with procedures that accept a list as
  665. input, or consumers. The concept of a stream is just a metaphor for a list
  666. that is not complete.
  667. A simple consumer is sum:
  668.  
  669.         -compile(free).
  670.         -exports([sum/2]).
  671.  
  672.         sum(L,R):-
  673.                 sum(L,0,R).
  674.  
  675.         sum([],Accum,R):-
  676.                 R := Accum.
  677.         sum([H|T],Accum,R):-
  678.                 integer(H) |
  679.                         Accum1 is Accum + H,
  680.                         sum(T,Accum1,R).
  681.         sum(L,_,R):-
  682.                 otherwise |
  683.                         R := error("invalid value",L).
  684.  
  685. The first feature to note is that this file contains two different
  686. procedures. Both have the same name, but different numbers of arguments
  687. (arity). The two procedures are sum/2 and sum/3, these are totally distinct
  688. as far as the Strand system is concerned. In practice, of course, it might be
  689. better to use different names, but that would miss the point. This example is
  690. similar to the previous example but uses a list construct in the head of
  691. sum/3 to decompose the list.
  692.  
  693. Try calling sum on a small list:
  694.  
  695.         10>demo3:sum([3,4,5],R1^)
  696.         R1 == 12
  697.         11>
  698.  
  699. We can tie together the producer and consumer by linking the two procedures.
  700. A module that does this look like:
  701.  
  702.         -compile(free).
  703.         -exports([go/1]).
  704.  
  705.         go(N):-
  706.                 integer(N) |
  707.                         demo2:gen(N,L),
  708.                         demo3:sum(L,R),
  709.                         output(R).
  710.         go(N):-
  711.                 otherwise |
  712.                         display_n1("Error: parameter should be an integer")!.
  713.  
  714.         output(R):-
  715.                 data(R) |
  716.                         display("The total is: ")&
  717.                         display_n1(R)!.
  718.  
  719.  
  720.  
  721. FOREIGN LANGUAGE INTERFACE
  722.  
  723. Strand's foreign language Interface provides a method for including new guard
  724. and body kernels within the Strand SAM, thus extending the set of available
  725. primitive calls. These "foreign language" kernels can be called from Strand
  726. programs compiled and run on the extended SAM, independent of the presence or
  727. absence of the Strand environment. Foreign language code (i.e. non Strand
  728. definitions) must be supplied to implement the kernel functionality. This
  729. code is called when kernels are executed, either during guard testing or
  730. activation of a clause body. The foreign code has access to the kernel
  731. arguments and may also build new Strand data for return as output. A number
  732. of foreign kernels are supplied with Strand (see the Strand Reference
  733. Manual).
  734.  
  735. The foreign language interface also enables users to extend the range of
  736. Strand datatypes available in the SAM. User datatypes can be used to store
  737. foreign language data structures for use by foreign code. Alternatively, they
  738. can be used to optimize access to and manipulation of data which could also
  739. be encoded using Strand structures such as tuples or lists.
  740.  
  741. The foreign language interface provides one more useful function. It enables
  742. external interrupt signals to be caught and handled without endangering the
  743. correct functioning of the SAM. The interrupt functionality is integrated
  744. with the kernel interface. It provides for enabling/disabling of interrupt
  745. signals, notification of interrupt signals to the SAM, registration of
  746. interrupt handlers to be called by the SAM and a stream interface between the
  747. handler and a Strand 'interrupt consumer' process.
  748.  
  749. A library definition file is a text file containing declarations of foreign
  750. kernels in a standard format. A declaration may spread over more than one
  751. line, but each new entry must start after a new line. It may also contain
  752. library file references, declarations to include kernel declarations from
  753. other library definition files. When malis (the program that generates the
  754. foreign kernel code) is called to build the interface code it must be
  755. provided with the name of a single libdef file as argument. It reads the file
  756. line by line recording each kernel declaration. When it reads a library file
  757. reference it inserts lines from the library definition file referred to in
  758. the declaration in place of the reference and continues processing. Once all
  759. include and kernel declarations have been read and noted malis generates the
  760. interface code used to invoke the foreign kernels declared in all the files
  761. it has read. N.B. malis will follow up nested library file references i.e. a
  762. library file included by a reference may contain other references which malis
  763. will look up and include.
  764.  
  765. A foreign kernel declaration has the following format:
  766.  
  767.         Number Type Strand_name Foreign_name Mode Language
  768.  
  769. The Mode is a list of argument mode specifiers, one per kernel argument,
  770. where a mode specifier is a symbol describing the argument. Up to 32
  771. arguments may be defined for a foreign goal, although the kernel may have
  772. none. The argument mode specifiers are written inside round brackets,
  773. separated by commas. Each argument mode specifier indicates whether the
  774. argument specified in the foreign kernel is an input or output argument. A
  775. question mark (?) denotes an input argument, a caret (^) denotes an output
  776. argument; a hyphen (-) denotes a raw argument i.e. one that Strand should
  777. pass directly to the foreign code. The question marks, carets and hyphens are
  778. separated by commas. Additionally the types of the arguments may be
  779. specified, in which case the code to convert the types from Strand to or from
  780. C or Fortran is generated automatically. If the foreign procedure returns a
  781. result then this may be specified by using a colon after the other parameters
  782. have been defined. For example:
  783.  
  784.   5103 guard s_cos cos (?) C       defines a kernel with one input argument
  785.   5104 guard s_tan tan(?,?) c      defines a kernel with two input arguments
  786.   5105 body s_sqrt sqrt(Real?):Real^ c   defines a kernel with its first    
  787.                                          argument an real input and it      
  788.                                          second an output real
  789.   5106 guard s_sin sin(-) c        defines a kernel with one raw argument
  790.  
  791.  
  792. FOREIGN LANGUAGE INTERFACE EXAMPLE
  793.  
  794. Here is an example of the Foreign Language Interface used to write 6 kernels
  795. to manipulate a database.
  796.  
  797. Firstly, the 6 'foreign' code procedures:
  798.  
  799. OPEN
  800.  
  801. Void open_db(name,dbu,res)
  802. REF name,dbu,res
  803.  
  804. Function - Opens database file identified by name.
  805.  
  806. Returns - Address of the database file in dbu and successful completion or
  807. returns failure message.
  808.  
  809. CLOSE
  810.  
  811. Void close_db(dbu,res)
  812. Ref dbu,res
  813.  
  814. Function - Closes database file identified by dbu
  815.  
  816. Returns - Success or failure
  817.  
  818. DATABASE
  819.  
  820. Void is_db(dbu)
  821. Ref dbu
  822.  
  823. Function - Checks whether the location identified by dbu is a database.
  824.  
  825. GET RECORD
  826.  
  827. Void get_rec(dbu,key,result)
  828. REF dbu,key,result
  829.  
  830. Function - Searches in the database identified by dbu, for record identified
  831. by key.
  832.  
  833. Returns - Record identified by key or failure if not found.
  834.  
  835. PUT RECORD
  836.  
  837. Void put_rec(dbu,key,contents,result)
  838. REF dbu,key,contents,result
  839.  
  840. Function - Puts contents in location identified by key in the database
  841. identified by dbu.
  842.  
  843. Returns - Successful put or an error.
  844.  
  845. DELETE RECORD
  846.  
  847. void delete_rec(dbu,key,result)
  848. REF dbu,key,result
  849.  
  850. Function - Deletes a record identified by key in database identified by dbu.
  851.  
  852. Returns - Successful deletion or error.
  853.  
  854. The corresponding library definition file entries for these 6 procedures are:
  855.  
  856. 201 body db_open open_db(?,^,^) c
  857. 202 body db_close close_db(?,^) c
  858. 203 guard database is_db(?) c
  859. 204 body db_get get_db(?,?,^) c
  860. 205 body db_put put_db(?,?,?,^) c
  861. 206 body db_delete delete_db(?,?,^) c
  862.  
  863. >From this library definition file, the program MALIS will produce the 6
  864. Strand user kernels which will allow access to the 6 procedures from within
  865. the Strand program.
  866.  
  867. Typical use of these kernels from within Strand would be:
  868. db(Name,Request)                                                
  869.         open(Name,Id,Result),                         % open requested database
  870.         dbm(Id,Request,Result).                       % send requests
  871.  
  872. dbm(Id,Request,Result) :-
  873.         data(Result) |                                % check ready to send
  874.                 dbm1(Id,Request).                     % next request
  875.  
  876. dbm1(Id,[get(Key,Result) | Request]) :-               % get request
  877.         get(Id,Key,Result), dbm(Id,Request,Result).
  878.  
  879. dbm1(Id,[put(Key,Rec,Result) | Request]) :-           % put request
  880.         put(Id,Key,Rec,Result), dbm(Id,Request,Result).
  881.  
  882. dbm1(Id,[delete(Key,Result) | Request]) :-            % delete request
  883.         delete(Id,Key,Result), dbm(Id,Request,Result).
  884.  
  885. dbm1(Id,[]) :-                                        % close request
  886.         close(Id,Result), dbm(Id,Request,Result)
  887.  
  888. open(Name,Id,Result):- database(Id) | db_open(Name,Id,Result).
  889. open(Name,Id,Result):- otherwise | Fail(Result).               % error
  890.  
  891. put(Id,Key,Record,Result):- database(Id) | db_put(Id,Key,Record,Result).
  892. put(Id,Key,Record,Result):- otherwise | Fail(Result).          % error
  893.  
  894. get(Id,Key,Result):- database(Id) | db_get(Id,Key,Result).
  895. get(Id,Key,Result):- otherwise | Fail(Result).                 % error
  896.  
  897. delete(Id,Key,Result):- database(Id) | db_delete(Id,Key,Result).
  898. delete(Id,Key,Result):- otherwise | Fail(Result).              % error
  899.  
  900. close(Id,Result):- database(Id) | db_close(Id,Result).
  901. close(Id,Result):- otherwise | Fail(Result).                   % error
  902.  
  903.  
  904. PERPETUAL PROCESSES AND DATA FLOW
  905.  
  906. Strand supports recursion and has recursive data structures.
  907. The basic idea of writing recursive algorithms is to express an algorithm in
  908. terms of itself with a set of stopping conditions. In Strand there is only
  909. one way to express iteration and that is through writing recursive or
  910. perpetual processes. These processes typically have the form:
  911.  
  912.                 my_process(....) :-
  913.                         G1,G2,...Gn |
  914.                                 B1,B2,my_process(....).
  915.  
  916.                 .
  917.                 .
  918.                 .
  919.                 my_process(...).
  920.  
  921. In this form there are a number of clauses which cause a new instance of
  922. "my_process" to be spawned if they are used to reduce this process. Thus the
  923. process is defined in terms of itself. Notice there is at least one
  924. termination clause which represents a stopping condition.
  925.  
  926. STREAMS
  927.  
  928. In Strand processes communicate through the use of shared variables, consider
  929. the following process pool:
  930.  
  931.                         producer(C), consumer(C)
  932.  
  933. These both share a common communication channel represented by the shared
  934. variable C. If this variable is a list and the tail of the list is always an
  935. unbound variable, then data can flow from producer to consumer through this
  936. data structure. An incomplete data structure of this type is known as a
  937. Stream.
  938.  
  939.  
  940. PROGRAMMING CLICHES
  941.  
  942. Programming cliches exist in all languages and are the building blocks from
  943. which all applications are designed.
  944.  
  945. In Strand there are 6 cliches:
  946.  
  947. 1. Producer/ Consumer
  948. 2. Incomplete messages
  949. 3. Bounded Buffers
  950. 4. Difference Lists
  951. 5. Short Circuits
  952. 6. Blackboards
  953.  
  954.  
  955. PROGRAMMING IN STRAND
  956.  
  957. Strand is a concurrent programming language that has parallel semantics (see
  958. portability). This does not mean however that all code written in Strand will
  959. run in parallel automatically. If processes are to run in parallel they must
  960. be coded in such a way that this is possible and correct (i.e. required data
  961. available, the correct communication data is set up).
  962.  
  963. Conversely, sequential algorithms can be successfully coded in Strand if
  964. desirable. This can be achieved by synchronization through shared data
  965. (remembering that Strand is a single assignment language and a process will
  966. suspend until data is available). But the affect of distributing sequential
  967. code over several nodes will be no different than executing on a single node
  968. machine.
  969.  
  970.  
  971. PORTABILITY
  972.  
  973. Strand has parallel semantics which means that the same code can be
  974. distributed in many different ways with no need to adapt the functionality .
  975. Distribution is achieved by annotation which does not affect the correctness
  976. of the program and can be tailored to achieve maximum performance results.
  977.  
  978. Alternatively, using a standard set of annotations will give adequate
  979. performance, but complete code invariance across many configurations.
  980.  
  981. In terms of user applications, providing STRAND88 is available on the
  982. particular hardware platform, there should be no problems in porting from one
  983. machine to another (assuming any external code included via the Foreign
  984. Language Interface, will port to the new machine). The user may change the
  985. annotation of process to processor for multi processor machines. This is
  986. possible because in between the user application and hardware there is the
  987. SAM (Strand Abstract Machine). This is the part of the system that does the
  988. low level emulation. A SAM must exist for the particular hardware the user
  989. wants to use (each SAM is written in 'C' and will vary slightly from machine
  990. to machine). If it does then running the same Strand code on the different
  991. machines should be possible.
  992.  
  993.  
  994.                  Portable Parallel Programming with Strand
  995.  
  996.                                  Abstract
  997.  
  998. Strand is a programming language for developing applications to run on a
  999. broad range of parallel computers. It is based on an inherently parallel
  1000. model. Therefore, the results from a Strand program are invariant to changes
  1001. in a program's parallelism. This paper will introduce the Strand language and
  1002. its interface to C and Fortran. A Strand/C program that predicts
  1003. characteristics of a protein's shape is described as an example of the
  1004. utility of Strand multilingual programming.
  1005.  
  1006.                                Introduction
  1007.  
  1008. The spread of parallel processing throughout the advanced computing arena is
  1009. restricted by a shortage of software. This scarcity of software is largely
  1010. due to the fact that each parallel computer has its own native programming
  1011. tools; a situation that binds an application program to a particular machine.
  1012.  
  1013. Lack of portable software hurts the industry from both ends of the user
  1014. spectrum. The supercomputing end user is reluctant to adopt parallel
  1015. processing due to the costs of parallelizing their programs for each
  1016. computer. The nonportability of the resulting programs makes parallel
  1017. computing a high risk endeavor.
  1018.  
  1019. Further exasperating the situation is the barrier placed before commercial
  1020. software vendors who need a broad market base in order to recoup their
  1021. investments. While the combined parallel computing market is large,
  1022. individual computers have too few users to support independent software
  1023. vendors. Therefore, with very few exceptions, third party software vendors
  1024. are staying away from the parallel processing market - denying users the
  1025. parallel math libraries, data base management systems and specific
  1026. applications they require.
  1027.  
  1028. Only with portable, parallel software development tools will parallel
  1029. computing be able to enter the mainstream of supercomputing. Two strategies
  1030. have been used to design these tools. One approach involves extending an
  1031. existing sequential language with parallel processing constructs. This is the
  1032. approach taken by Schedule [1] and Linda [2]. Alternatively, a new,
  1033. inherently parallel processing language can be developed such as ALP [3] or
  1034. Strand [4].
  1035.  
  1036. Selecting the preferred strategy is a subjective decision based to some
  1037. degree on the applications under consideration. It is my opinion, however,
  1038. that the best long range choice is a new, inherently parallel processing
  1039. language. This type of language has a better chance of evolving with the
  1040. state of the art in advanced computing. As automatic parallelization
  1041. techniques become available, the importance of inherently parallel languages
  1042. will increase since they should map better into these schemes.
  1043.  
  1044. The only inherently parallel programming language commercially available on
  1045. a broad range of computers is STRAND88. This language runs on sequential
  1046. computers as well as distributed memory and shared memory parallel computers.
  1047. The goal of this paper is to introduce the Strand language and how it is
  1048. currently being used to develop applications. The paper begins with a brief
  1049. description of the language. This is followed by a simple example to solidify
  1050. the preceding language summary. Next, the details behind calling C and
  1051. Fortran subprograms are given followed by a program to compute the linear
  1052. convolution of two arrays. This demonstrates both the use of C functions in
  1053. a Strand program and explicit parallelism in Strand. The paper concludes with
  1054. a discussion of current Strand applications with an emphasis on a protein
  1055. structure program developed at Caltech [5].
  1056.  
  1057.                             The Strand Language
  1058.  
  1059. The key to any portable parallel processing language is its architecture
  1060. independent view of the parallel computer. Figure one displays the Strand
  1061. computational model. The central feature of this model is the pool of light
  1062. weight processes representing the state of the computation.
  1063.  
  1064. -----------------------------------------------------------------------------
  1065.                  Figure 1: The Strand computational model
  1066.  
  1067.    -------------                              -------------------
  1068.    | Strand    |----------------------------> |                 |
  1069.    | Abstract  |                              |   Process Pool  |
  1070.    | Machine   | <----------------------------|                 |
  1071.    -------------                              |        O        |
  1072.       ^  ^  ^                                 |    O       O    |
  1073.      /   |   \                                |  O              |
  1074.    -------------------                        |                 |
  1075.    |    module 1     |                        |   O      O      |
  1076.    |                 |                        |              O  |
  1077.    | proc1(...):-... |                        |       O         |
  1078.    | proc2(...):-... |                        |            O    |
  1079.    | proc3(...):-... |                        |   O       O     |
  1080.    -------------------                        -------------------
  1081. -----------------------------------------------------------------------------
  1082.  
  1083. A Strand computation cycle begins when the Strand Abstract Machine (SAM)
  1084. removes a process from the pool. The SAM reduces this process into more
  1085. primitive processes using the information from the Strand program. These
  1086. processes are either placed back into the pool or, if they are so primitive
  1087. as to be immediately executable, they are executed. These executable
  1088. processes are referred to as kernels.
  1089.  
  1090. Strand kernels fall into two classes - user defined and language provided.
  1091. Language provided kernels consist of assignment, scaler arithmetic, and other
  1092. low level operations. User defined kernels are Fortran and C routines
  1093. provided by the user. The interface between user defined routines and Strand
  1094. is discussed in more detail in a later section.
  1095.  
  1096. In all cases, a process suspends until all of its required data is available.
  1097. Hence, Strand can be viewed as a data flow language.
  1098.  
  1099. As mentioned earlier, Strand processes are reduced according to the rules
  1100. from the Strand program. The Strand program consists of a collection of
  1101. modules containing Strand procedures. Hence we must understand the syntax of
  1102. a Strand procedure. A full description of Strand's syntax is available in the
  1103. textbook Strand: New Concepts in Parallel Programming [4]. Only a summary is
  1104. given here.
  1105.  
  1106. A Strand procedure consists of a collection of clauses with the same name.
  1107. The form of a clause is:
  1108.  
  1109.      H :- G1, G2, ... GM | B1, B2, ... BP.
  1110.  
  1111. H is the head of the clause. It contains the clause's name and the procedure
  1112. arguments. G1 through GM are the optional guard kernels which provide tests
  1113. of the procedure arguments. Finally, if the head matches the process being
  1114. reduced, the guards all succeed, and all of the required data is available,
  1115. then the optional body calls, B1 through BP, are activated. The body calls
  1116. can be other Strand procedures or body kernels.
  1117.  
  1118. Strand variables are single assignment and are indicated by an initial
  1119. uppercase letter. Processes share variables to communicate with each other.
  1120.  
  1121. Strand's simple data types are integer, real and string. These are self
  1122. explanatory. The compound types are the list and the tuple.
  1123.  
  1124. The list is defined as a collection of comma separated items:
  1125.  
  1126.      [1, 4, 2.0, "a string", Variable_1]
  1127.  
  1128. Lists elements are accessed using a head - tail notation:
  1129.  
  1130.      [H1 | Tail]
  1131.  
  1132. where H1 refers to the first element of the list and Tail to the rest of the
  1133. list.
  1134.  
  1135. A tuple is a more general form of a list. While a list is processed
  1136. sequentially, the elements of a tuple are accessed randomly. Tuples are in
  1137. some ways simpler than lists but will not be considered further in this
  1138. paper.
  1139.  
  1140. The computational model underlying Strand is inherently parallel. STRAND88,
  1141. however, does not automatically distribute processes across the nodes of a
  1142. parallel computer. The programmer must explicitly assign a process to a node.
  1143. For example, the body call to invoke the process, conv, on node N, is:
  1144.  
  1145.      conv(Argument_list)@N,
  1146.  
  1147. The node address can be a variable, a literal or in some cases a virtual
  1148. address such as next or previous. The syntax of interprocess communication
  1149. does not depend on whether the processes reside on the same node or not.
  1150. Hence, the result of a Strand program does not change as the explicit
  1151. parallelism is modified.
  1152.  
  1153. This discussion of Strand's syntax will be much clearer after considering the
  1154. following example.
  1155.                          Example: List Membership
  1156.  
  1157.  
  1158. Consider the procedure member. The procedure's three clauses define the
  1159. search of an input list for the indicated KEY. If it finds KEY the variable
  1160. Status is set to the string "ok" . Otherwise, Status is set to "fail".
  1161.  
  1162. The Strand Abstract Machine, SAM, would select the member procedure to reduce
  1163. a process of that name. The head of the procedure's first clause will
  1164. successfully match to a process with a non empty list for its second
  1165. argument. Note that the input list is split into its head and tail during the
  1166. matching. If the guard succeeds, Status is set to ok and the procedure
  1167. terminates.
  1168.  
  1169. If the head matches but the guard from the first clause fails, the second
  1170. clause is attempted. If this guard succeeds, the member procedure is
  1171. recursively invoked on the tail of the list.
  1172.  
  1173. Finally, if the second argument of the process being reduced is an empty
  1174. list, only the head of the third clause can successfully match. This
  1175. indicates that the key was never found in the list and Status is set to the
  1176. string fail.
  1177.  
  1178. -----------------------------------------------------------------------------
  1179.                   Figure 2: The list membership procedure
  1180.  
  1181. member(Key, [Head | Tail], Status) :-
  1182.      Key == Head |
  1183.           Status := ok.
  1184. member(Key, [Head | Tail], Status) :-
  1185.      Key =/= Head |
  1186.           member(Key, Tail, Status).
  1187. member(Key, [], Status) :-
  1188.      Status := fail.
  1189. -----------------------------------------------------------------------------
  1190.  
  1191. This discussion implied that the Strand Abstract Machine considered the three
  1192. clauses in sequential order. This is not required by the language. The
  1193. programmer just provides for all cases that can arise during process
  1194. reduction and does not have to worry about the order of the clauses.
  1195.  
  1196.  
  1197.                       The Foreign Function Interface
  1198.  
  1199. STRAND88 is a complete language providing all the constructs needed to
  1200. develop interesting applications. It would be of limited practical value,
  1201. however, if it could not call routines written in C and Fortran. Many
  1202. parallel algorithms contain large sequential segments. Hence, an effective
  1203. programming strategy is to embed sequential program fragments in the parallel
  1204. Strand program. This is easy to express with Strand as any body or guard
  1205. kernel can be replaced by a call to a C or Fortran routine.
  1206.  
  1207. To call a Fortran or C routine from Strand, the programmer must build a SAM
  1208. executable image that includes the foreign code. This is done using
  1209. information from a user created library definition file. This file defines
  1210. the mapping between Strand and the foreign code including procedure names and
  1211. argument types. Once the new SAM has been built, foreign routines can be used
  1212. just like any other Strand guard or body kernel.
  1213.  
  1214. STRAND88 includes a library of macros and functions to manipulate Strand data
  1215. types within Fortran and C routines. One can also create user defined,
  1216. foreign data types that can be passed between processes through the shared
  1217. variable mechanism.
  1218.  
  1219. The following example demonstrates the use of the foreign function interface
  1220. with a parallel algorithm.
  1221.  
  1222.  
  1223.                    Example: Parallel Linear Convolution
  1224.  
  1225. Linear convolution [6] is a fundamental algorithm of digital signal
  1226. processing. This section of the paper presents a procedure that returns the
  1227. linear convolution of two equal length arrays. If the two input arrays, X and
  1228. H, are of length NX, then the output array, Y, is of length (2*NX-1).
  1229.  
  1230. The algorithm is easily parallelized since each value in the convolution is
  1231. computed independently. A C function was written that computes a block of
  1232. convolution values starting at a given index. Therefore, each node is given
  1233. a different block of the convolution to perform. All nodes use the same C
  1234. function. The function declaration is:
  1235.  
  1236.      void conv(ind, size, n, nh, h, nx, x, ny, y)
  1237.      int ind, size, n, nx, ny, *ny;
  1238.      double h[], x[], *y[];
  1239.  
  1240. where the output values, ny and y, are pointers to the appropriate type. This
  1241. function will return in y the next size results of the convolution starting
  1242. with y [ind] . The Strand procedure call that maps to this function is:
  1243.  
  1244.      conv(Ind, Size, N, H, X, Y)
  1245.  
  1246. where H, X and Y are lists. Notice that each Strand list maps into two values
  1247. - an integer representing the length of the array and a double array.
  1248.  
  1249. Figure 3 presents the code for a procedure called convolution. This procedure
  1250. will fill the array Y with the convolution of the two input arrays, X and H.
  1251. An array in Strand is represented as a list of real values (though the
  1252. experienced reader may notice that Y is a list of lists - one for each block
  1253. of the convolution).
  1254.  
  1255. The input to the procedure is the number of elements to use from X and H
  1256. (NX), the requested number of nodes (Nodes), and the lists representing the
  1257. input arrays (X and H) . The first clause of the procedure computes the block
  1258. size for the convolution and the actual number of nodes to use. Notice that
  1259. // is the modulus operator. When all of the data is ready, the procedure that
  1260. does the convolution (conv1) is activated.
  1261.  
  1262. The conv1 procedure consists of two clauses. The first clause handles all but
  1263. the last block of the convolution and recursively calls itself to initiate
  1264. computation for subsequent blocks. These are the fixed blocks of size Size.
  1265. The second conv1 clause handles the last block which may have a different
  1266. size. Both clauses invoke a Strand procedure, worker, that calls the C
  1267. function.
  1268.  
  1269. This example contains a great deal of information. To appreciate its
  1270. operation, remember that the procedures all run concurrently and, except for
  1271. data flow synchronization, independently. The node addresses wrap around for
  1272. cases where there are fewer nodes than requested by the algorithm.
  1273.  
  1274. -----------------------------------------------------------------------------
  1275.                  Figure 3: Parallel convolution procedure.
  1276.  
  1277.      convolution(Nodes, NX, X, H, Y) :-
  1278.                NY is 2 * NX - 1,
  1279.                ModNY is NY // Nodes,
  1280.                comp_bsize(Nodes, NY, ModNY, Size, NodesToUse),
  1281.                conv1(NodesToUse, 0, NY, Size, NX, X, H, Y).
  1282.  
  1283.      conv1( Node, Index, NY, Size, NX, X, H, Y) :-
  1284.           Node > 0 |
  1285.                NewInd is Index + Size,
  1286.                NewNode is Node - 1,
  1287.                worker(Size, Index, NX, X, H, YHere)@Node,
  1288.                Y := [YHere | YRest],
  1289.                conv1(NewNode, NewInd, NY, Size, NX, X, H, YRest).
  1290.      conv1(0, Index, NY, Size, NX, X, H, Y) :-
  1291.                Length is NY - Index,
  1292.                worker(Length, Index, NX, X, H, Y)@0.
  1293.  
  1294.      worker(Length, Index, NY, X, H, Y) :-
  1295.                conv(Index, Length, NY, H, X, Y).
  1296.  
  1297.      comp_bsize(Nodes, NY, O, Size, NodesToUse) :-
  1298.                NodesToUse := Nodes,
  1299.                Size is NY / Nodes.
  1300.      comp_bsize(Nodes, NY, ModNY, Size, NodesToUse) :-
  1301.           ModNY > O |
  1302.                Size is 1 + NY / Nodes,
  1303.                NodesToUse is NY / Size.
  1304. -----------------------------------------------------------------------------
  1305.  
  1306.                                Applications
  1307.  
  1308. STRAND88 is being used for a number of research projects ranging from
  1309. numerically intensive applications such as weather modeling [7] and protein
  1310. structure determination [5] to abstract pattern matching problems such as the
  1311. human Genome project [4]. This section will focus on the protein structure
  1312. work.
  1313.  
  1314. The three dimensional shape of a protein is a critical property for
  1315. understanding the function of a protein. Full determination of protein shapes
  1316. is a vast problem taxing the abilities of the fastest supercomputers. A
  1317. valuable preliminary step is to predict where the protein folds into a
  1318. particular shape known as an alpha helix.
  1319.  
  1320. Two Caltech chemists, Joe Bryngelson and John Hopfield [5] developed a
  1321. sequential C program that learns how to predict alpha Helix locations. The
  1322. program learns how to predict alpha helices for new proteins by carrying out
  1323. a large nonlinear optimization calculation with known protein structures.
  1324.  
  1325. Stephen Taylor and Sam Southard [5] parallelized this sequential program
  1326. using STRAND88 to express the parallel parts of the algorithm. 75% of the
  1327. original C code was used in the final parallel program. Furthermore, Strand's
  1328. management of the parallelism was very flexible allowing easy experimentation
  1329. with different schemes for parallel execution.
  1330.  
  1331. The program displays linear speedup with up to 32 nodes. The drop off from
  1332. linearity at 64 nodes is an artifact of the protein data set divided among
  1333. 64 nodes. A larger data set would allow the program to show linear speed up
  1334. beyond 32 nodes.
  1335.  
  1336. The logic required to manage parallelism inevitably carries a cost. The cost
  1337. incurred by the Strand/C program is small and is overcome by the time the
  1338. second node is added.
  1339.  
  1340.                                 Conclusion
  1341.  
  1342. The Strand language was first offered commercially in the summer of 1989. In
  1343. a relatively short time it has established itself as a powerful parallel
  1344. programming language.
  1345.  
  1346. Strand applications research is progressing at an increasing rate as the
  1347. number of users grows. It is proving to be a useful language in the
  1348. numerically intensive areas with current research projects in seismic signal
  1349. processing [8] and computational fluid dynamics.
  1350.  
  1351. While the parallel processing industry is still a long way from adopting
  1352. programming language standards, it is hoped that STRAND88 will play a key
  1353. role in filling this void. To this end, future work with Strand will focus
  1354. on both improving the language and on building a large collection of
  1355. applications.
  1356.  
  1357.  
  1358.                                 References
  1359.  
  1360. [1] J. Dongarra and D. Sorenson. "SCHEDULE: Tools for developing and
  1361.      analyzing parallel Fortran programs" in The Characteristics of Parallel
  1362.      Algorithms, MIT Press, 1987.
  1363.  
  1364. [2] W. Leler. "Linda Meets Unix", IEEE Computer, Feb. 1990, page 43.
  1365.  
  1366. [3] P. Vishnubhotla. "Concurrency and Synchronization in the ALPS Programming
  1367.      Language". Ohio State University Technical Research Report,
  1368.      OSU-CISRC-12/89-TR56, 1989.
  1369.  
  1370. [4] Ian Foster and Steve Taylor, Strand: New Concepts in Parallel
  1371.      Programming, Prentice Hall, 1990.
  1372.  
  1373. [5] S. Southard Jr. "A Parallel Algorithm for Alpha Helix Prediction", Draft,
  1374.      March 12, 1990.
  1375.  
  1376. [6] A. V. Oppenheim, R.W. Schafer. Digital Signal Processing. Prentice Hall,
  1377.      1975.
  1378.  
  1379. [7] I. Foster, R. Overbeek. "Experiences with Bilingual Parallel
  1380. Programming".  Presentation at the Fifth Distributed Memory Computing
  1381.                Conference, 1990.
  1382.  
  1383. [8] T. G. Mattson, K. Steer. "The Seismic Signal Processing Workbench", SSTI
  1384.      Internal document, 1990.
  1385.